package lipengfei.botaiframework.security.jwt.filter;

import cn.hutool.core.util.StrUtil;
import lipengfei.botaiframework.jwt.JwtConst;
import lipengfei.botaiframework.jwt.JwtUtil;
import lipengfei.botaiframework.security.jwt.authentication.JWTAuthenticationManager;
import lipengfei.botaiframework.security.jwt.exception.impl.JWTExpiredException;
import lipengfei.botaiframework.security.jwt.handler.TokenExpiredHandler;
import lipengfei.botaiframework.security.jwt.handler.TokenInvalidHandler;
import lipengfei.botaiframework.security.jwt.handler.TokenRefreshHandler;
import lipengfei.botaiframework.security.jwt.handler.TokenSuccessHandler;
import lipengfei.botaiframework.security.jwt.userdetails.AbstractUserDetailsService;
import lipengfei.botaiframework.security.jwt.userdetails.OnlineUser;
import lipengfei.botaiframework.security.jwt.validator.ValidationResult;
import lipengfei.botaiframework.security.jwt.validator.ValidatorModel;
import lipengfei.botaiframework.security.jwt.validator.eunm.ValidationState;
import lipengfei.botaiframework.utils.cache.ThreadLocalCache;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JwtTokenFilter extends BasicAuthenticationFilter {

    private String TOKEN_HEADER_NAME;

    private String REFRESH_TOKEN_HEADER_NAME;

    private JWTAuthenticationManager jwtAuthenticationManager;

    private TokenRefreshHandler tokenRefreshHandler;

    private TokenExpiredHandler tokenExpiredHandler;

    private TokenSuccessHandler tokenSuccessHandler;

    private TokenInvalidHandler tokenInvalidHandler;

    private AbstractUserDetailsService userDetailsService;


    public JwtTokenFilter(
            AuthenticationManager authenticationManager,
            String TOKEN_HEADER_NAME,
            String REFRESH_TOKEN_HEADER_NAME,
            JWTAuthenticationManager jwtAuthenticationManager,
            TokenRefreshHandler tokenRefreshHandler,
            TokenExpiredHandler tokenExpiredHandler,
            TokenSuccessHandler tokenSuccessHandler,
            TokenInvalidHandler tokenInvalidHandler,
            AbstractUserDetailsService userDetailsService) {
        super(authenticationManager);
        this.TOKEN_HEADER_NAME = TOKEN_HEADER_NAME;
        this.REFRESH_TOKEN_HEADER_NAME = REFRESH_TOKEN_HEADER_NAME;
        this.jwtAuthenticationManager = jwtAuthenticationManager;
        this.tokenRefreshHandler = tokenRefreshHandler;
        this.tokenExpiredHandler = tokenExpiredHandler;
        this.tokenSuccessHandler = tokenSuccessHandler;
        this.tokenInvalidHandler = tokenInvalidHandler;
        this.userDetailsService = userDetailsService;
    }


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
       String url= request.getRequestURI();
        System.out.println(url);
        String jwtToken = request.getHeader(TOKEN_HEADER_NAME);
        String jwtRefreshToken = request.getHeader(REFRESH_TOKEN_HEADER_NAME);

        if (StrUtil.isNotBlank(jwtToken)  &&  StrUtil.isNotBlank(jwtRefreshToken) ) {
            ValidationResult result = jwtAuthenticationManager.validate(new ValidatorModel(jwtToken,jwtRefreshToken));

            if (result.getValidationState() == ValidationState.SUCCESS) {

                String userName = JwtUtil.getClaim(jwtToken, JwtConst.ACCOUNT);
                OnlineUser onlineUser = (OnlineUser) userDetailsService.loadUserByUsername(userName);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(onlineUser, null, onlineUser.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authentication);
                ThreadLocalCache.set("onlineUserId", onlineUser.getUserId());
                tokenSuccessHandler.handle(request, response);

            }else if (result.getValidationState() == ValidationState.NEED_REFRESH) {

                String userName = JwtUtil.getClaim(jwtToken, JwtConst.ACCOUNT);
                OnlineUser onlineUser = (OnlineUser) userDetailsService.loadUserByUsername(userName);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(onlineUser, null, onlineUser.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authentication);
                ThreadLocalCache.set("onlineUserId", onlineUser.getUserId());

                tokenRefreshHandler.handle(request, response);

            } else if (result.getValidationState() == ValidationState.EXPIRED) {
                tokenExpiredHandler.handle(request, response);

            }  else if (result.getValidationState() == ValidationState.ERROR) {
                tokenInvalidHandler.handle(request, response);
            }
        }
        chain.doFilter(request, response);
    }



}
